using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using SimpleJSON;
using Unity.Services.Core;
using UnityEngine;
using UnityEngine.Networking;

namespace Gj.UnityCloud
{
    public class Api : CertificateHandler
    {
        public const string SERVER_URL = "https://services.api.unity.com";
        public const string AUTH_URL = "https://player-auth.services.api.unity.com/v1";
        public static Api Instance;

        public static string AccessToken;
        public static JSONObject Custom;

        static Api()
        {
            Instance = new Api();
        }

        // https://services.docs.unity.com/docs/service-account-auth/#authenticate-an-api-using-a-stateless-token
        public static async Task<string> TokenExchange()
        {
            if (!string.IsNullOrEmpty(AccessToken)) return AccessToken;

            var header = new JSONObject();
            header["Authorization"] = $"Basic {UnityCloud.settings.Authorization}";
            var data = new JSONObject();
            var scopes = new JSONArray();
            scopes.Add("player_auth.server.custom_id_auth");
            data["scopes"] = scopes;
            var result = await Post(SERVER_URL+"/auth/v1/token-exchange?projectId="+UnityCloud.settings.ProjectId+"&environmentId="+UnityCloud.settings.EnvironmentId, data, header);
            await Task.Delay(5000);
            AccessToken = result["accessToken"];
            return AccessToken;
        }

        // https://services.docs.unity.com/player-auth/v1/index.html#tag/Player-Authentication/operation/SignInWithCustomID
        public static async Task<JSONObject> CustomIdLogin(string externalId, bool signInOnly, string accessToken)
        {
            if (Custom != null) return Custom;

            var header = new JSONObject();
            // header.Add("ProjectId", UnityCloud.settings.ProjectId);
            header.Add("UnityEnvironment", UnityCloud.settings.Environment);
            header["Authorization"] = $"Bearer {accessToken}";
            var data = new JSONObject();
            data["externalId"] = externalId;
            data["signInOnly"] = signInOnly;
            var result =
                await Post(
                    AUTH_URL + "/projects/{ProjectId}/authentication/server/custom-id".Replace("{ProjectId}",
                        UnityCloud.settings.ProjectId), data, header);
            await Task.Delay(5000);
            Custom = result != null ? result.AsObject : null;
            return Custom;
        }
        public static Task<JSONNode> Get(string url, JSONObject data, JSONObject header = null)
        {
            var taskCompletionSource = new TaskCompletionSource<JSONNode>();

            Game.single.StartCoroutine(Get(url, data, header, (result)=>taskCompletionSource.SetResult(result)));

            return taskCompletionSource.Task;
        }
        public static Task<JSONNode> Post(string url, JSONObject data, JSONObject header = null)
        {
            var taskCompletionSource = new TaskCompletionSource<JSONNode>();

            Game.single.StartCoroutine(Post(url, data, header, (result)=>taskCompletionSource.SetResult(result)));

            return taskCompletionSource.Task;
        }
        protected override bool ValidateCertificate(byte[] certificateData)
        {
            Debug.LogError("ValidateCertificate");
            //return base.ValidateCertificate(certificateData);
            return true;
        }

        public static IEnumerator Get(string url, JSONObject data, JSONObject header, Action<JSONNode> result)
        {
            UnityWebRequest webRequest = new UnityWebRequest(url,UnityWebRequest.kHttpVerbGET);

            webRequest.downloadHandler = new DownloadHandlerBuffer();
            webRequest.timeout = 5;

            //拥有对CertificateHandler对象的引用，该对象可管理此UnityWebRequest的证书验证
            webRequest.certificateHandler = Instance;

            webRequest.SetRequestHeader("Content-Type","text/json;charset=utf-8");
            if (header != null && header.Count > 0)
            {
                var e = header.GetEnumerator();
                var o = new JSONObject();
                while (e.MoveNext())
                {
                    var current = (KeyValuePair<string, JSONNode>)e.Current;
                    webRequest.SetRequestHeader(current.Key, current.Value.ToString());
                }
            }
            yield return webRequest.SendWebRequest();
            if (webRequest.isDone)
            {
                var info = JSONNode.Parse(webRequest.downloadHandler.text);
                result(info);
            }
            else
            {
                result(null);
            }
        }


        public static IEnumerator Post(string url, JSONObject data, JSONObject header, Action<JSONNode> result)
        {
            Debug.LogError("send url:"+url+" -> "+data.ToString());
            UnityWebRequest.ClearCookieCache();
            UnityWebRequest webRequest = UnityWebRequest.Post(url, data == null ? "" : data.ToString(), "application/json");
            UnityWebRequest.ClearCookieCache();

            webRequest.timeout = 10;
            //拥有对CertificateHandler对象的引用，该对象可管理此UnityWebRequest的证书验证
            webRequest.certificateHandler = Instance;
            webRequest.SetRequestHeader("Content-Type","application/json");
            if (header != null && header.Count > 0)
            {
                var e = header.GetEnumerator();
                var o = new JSONObject();
                while (e.MoveNext())
                {
                    var current = (KeyValuePair<string, JSONNode>)e.Current;
                    Debug.LogError($"Header {current.Key}: {current.Value.Value}");
                    webRequest.SetRequestHeader(current.Key, current.Value.Value);
                }
            }
            webRequest.SendWebRequest();
            while (!webRequest.isDone)
            {
                yield return new WaitForSeconds(1f);
                Debug.LogError($"process: {webRequest.uploadProgress} {webRequest.downloadProgress} {webRequest.error}");
            }
            if (webRequest.isDone)
            {
                var info = JSONNode.Parse(webRequest.downloadHandler.text);
                result(info);
            }
            else
            {
                result(null);
            }
        }
    }
}